package com.killer.sqlSession;

import com.killer.pojo.Configuration;
import com.killer.pojo.MappedStatement;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    //这里需要跟数据库进行交互，完成jdbc操作，因此这里需要configuration对象
    private Configuration configuration;
    private Executor executor;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration=configuration;
        executor=new SimpleExecutor();
    }

    @Override
    public <T> List<T> selectList(String statementId, Object... params) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //根据statementId，获取MappedStatment对象
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        //通过委派executor去执行jdbc代码
        List<T> t = executor.query(configuration, mappedStatement, params);
        return t;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws ClassNotFoundException, SQLException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        List<T> list = selectList(statementId, params);
        if (list == null || list.size() == 0 || list.size() > 1) {
            throw new RuntimeException("返回结果为空或大于1条记录");
        }
        return list.get(0);
    }

    @Override
    public int update(String statementId, Object... params) throws ClassNotFoundException, SQLException, IllegalAccessException, NoSuchFieldException {
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        //委派给executor执行insert操作
        return executor.update(configuration,mappedStatement,params);
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        //通过传入的接口类型，动态生成对应的实现类
        Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(),new Class[]{mapperClass} ,
                new InvocationHandler() {
                    //当目标对象调用任意方法时，都会被该方法拦截
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //获取该方法所在的类全类名
                        Class<?> mapperClass = method.getDeclaringClass();
                        //statementId就是   全类名.方法名  mapper文件遵循约定
                        String statementId=mapperClass.getName()+"."+method.getName();
                        //获取对应的mappedStatement
                        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
                        //这里根据opType去选择是调用select还是update还是insert还是delete
                        if ("select".equals(mappedStatement.getOpType())) {
                            //获取返回值类型
                            Type genericReturnType = method.getGenericReturnType();
                            //如果里面包换泛型,证明是返回list的
                            if (genericReturnType instanceof ParameterizedType) {
                                return selectList(statementId, args);
                            }else{
                                return selectOne(statementId, args);
                            }
                        }else{
                            return update(statementId, args);
                        }
                    }
                });
        return (T)o;
    }
}
